package com.keba.lamp.ai.strategy;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.dashscope.audio.asr.transcription.*;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.keba.basic.cache.repository.CacheOps;
import com.keba.basic.cache.repository.CachePlusOps;
import com.keba.basic.exception.BizException;
import com.keba.basic.model.cache.CacheHashKey;
import com.keba.basic.utils.ArgumentAssert;
import com.keba.lamp.ai.entity.*;
import com.keba.lamp.ai.service.*;
import com.keba.lamp.ai.vo.query.AiCallModelQuery;
import com.keba.lamp.ai.vo.query.AiCallModelRequestQuery;
import com.keba.lamp.ai.vo.result.AlibabaAiAudioResultVO;
import com.keba.lamp.common.cache.base.ai.AiAudioFileCacheKeyBuilder;
import com.keba.lamp.model.enumeration.BooleanEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;


@Slf4j
public abstract class AbstractApiCallStrategy implements ApiCallStrategy {


    @Resource
    private AiApiKeyService aiApiKeyService;
    @Resource
    private AiApplicationService aiApplicationService;
    @Resource
    private AiEndPointService aiEndPointService;
    @Resource
    private AiModelVersionService aiModelVersionService;
    @Resource
    private AiInvokeFileService aiInvokeFileService;
    @Resource
    private AiInvokeRecordService aiInvokeRecordService;

    @Resource
    private CachePlusOps cachePlusOps;

    @Resource
    private Environment environment;



    @Override
    public Object call(AiCallModelRequestQuery aiCallModelRequestQuery) {
        AiApplication aiApplication = aiApplicationService.getById(aiCallModelRequestQuery.getAppId());
        ArgumentAssert.notNull(aiApplication, "应用不存在");
        boolean isExist = aiApiKeyService.getSuperManager().exists(Wrappers.lambdaQuery(AiApiKey.class).eq(AiApiKey::getApiKey, aiCallModelRequestQuery.getAppKey()).eq(AiApiKey::getCustomerId, aiApplication.getCustomerId()));
        ArgumentAssert.isTrue(isExist, "应用密钥不存在");
        AiEndPoint aiEndPoint = aiEndPointService.getSuperManager().getOne(Wrappers.lambdaQuery(AiEndPoint.class).eq(AiEndPoint::getCustomerId, aiApplication.getCustomerId()).eq(AiEndPoint::getId, aiApplication.getEndPointId()));
        AiModelVersion aiModelVersion = aiModelVersionService.getById(aiEndPoint.getModelVersionId());
        ArgumentAssert.notNull(aiModelVersion,"模型不存在");
        AiInvokeRecord aiInvokeRecord = aiInvokeRecordService.save(AiInvokeRecord.builder().bizId(aiCallModelRequestQuery.getBizId()).applicationId(aiApplication.getId()).endPointId(aiEndPoint.getId()).modelId(aiModelVersion.getModelId()).modelVersionId(aiModelVersion.getId()).prompt(aiCallModelRequestQuery.getUserPrompt()).customerId(aiApplication.getCustomerId()).build());
        List<AiInvokeFile> aiInvokeFiles = new ArrayList<>();
        // 保存文件
        aiCallModelRequestQuery.getCompletionContents().forEach(o -> {
            aiInvokeFiles.add(AiInvokeFile.builder().invokeRecordId(aiInvokeRecord.getId()).type(o.getType()).content(o.getFileUrl()).build());
        });
        aiInvokeFileService.saveBatch(aiInvokeFiles);
        Map<String, Object> objectMap = aiCallModelRequestQuery.getExtra();
        if (Objects.nonNull(objectMap)) {
            objectMap.forEach((key, value) -> {
                // 替换prompt中的变量
                aiApplication.setPrompt(StrUtil.replace(aiApplication.getPrompt(), key, value.toString()));
            });
        }

        try {

            Object result = call(AiCallModelQuery.builder().modelId(aiModelVersion.getLlmModelId()).systemPrompt(aiApplication.getPrompt()).userPrompt(aiCallModelRequestQuery.getUserPrompt()).completionContents(aiCallModelRequestQuery.getCompletionContents()).build());
            aiInvokeRecordService.updateById(aiInvokeRecord.setResult(result.toString()).setState(BooleanEnum.TRUE.getInteger()));
            return result;
        } catch (Exception e) {
            log.error("应用ID：{},Ai模型调用失败", aiCallModelRequestQuery.getAppId(), e);
            aiInvokeRecordService.updateById(aiInvokeRecord.setState(BooleanEnum.FALSE.getInteger()));
            throw new BizException("调用失败");
        }
    }

    protected abstract Object call(AiCallModelQuery aiCallModel);


    protected List<AlibabaAiAudioResultVO> callAudio(List<String> audioUrls) {
        List<AlibabaAiAudioResultVO> results = new ArrayList<>();
        if (CollUtil.isEmpty(audioUrls)) {
            return results;
        }
        audioUrls.forEach(url -> {
            CacheHashKey hashKey = AiAudioFileCacheKeyBuilder.builder(url);
            if (cachePlusOps.hExists(hashKey)) {
                results.add((AlibabaAiAudioResultVO) cachePlusOps.hGet(hashKey, true).getValue());
                audioUrls.remove(url);
            }
        });
        TranscriptionParam param = TranscriptionParam.builder().apiKey(environment.getProperty("lamp.ai.audio.appId")).model("paraformer-v2").parameter("language_hints", new String[]{"zh", "en"}).fileUrls(audioUrls).build();
        try {
            Transcription transcription = new Transcription();
            // 提交转写请求
            TranscriptionResult result = transcription.asyncCall(param);
            // 等待转写完成
            log.info("CallAudio RequestId: " + result.getRequestId());
            result = transcription.wait(TranscriptionQueryParam.FromTranscriptionParam(param, result.getTaskId()));
            // 获取转写结果
            List<TranscriptionTaskResult> taskResultList = result.getResults();
            if (CollUtil.isNotEmpty(taskResultList)) {
                for (TranscriptionTaskResult taskResult : taskResultList) {
                    String transcriptionUrl = taskResult.getTranscriptionUrl();
                    HttpURLConnection connection = (HttpURLConnection) new URL(transcriptionUrl).openConnection();
                    connection.setRequestMethod("GET");
                    connection.connect();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                    Gson gson = new GsonBuilder().setPrettyPrinting().create();
                    AlibabaAiAudioResultVO aiAudioResultVO = gson.fromJson(reader, AlibabaAiAudioResultVO.class);
                    results.add(aiAudioResultVO);
                    cachePlusOps.hSet(AiAudioFileCacheKeyBuilder.builder(aiAudioResultVO.getFile_url()), aiAudioResultVO);
                }
            }
        } catch (Exception e) {
            log.error("CallAudio error: {}", e.getMessage(), e);
        }
        return results;
    }



}
